[Lang] 정수형 크기(uint16_t)와 비트·바이트 메모리 저장 원리

핵심 질문:
uint16_t msg_type은 2바이트인데, 어떻게 1001이라는 숫자를 담을 수 있는가?
“2바이트니까 10진수 2자리(0~99)만 들어가는 것 아닌가?” 또는 “1001은 4글자니까 4바이트가 필요한 게 아닌가?”라는 흔한 의문을 완벽히 해소한다.


1. 2바이트(uint16_t)의 실제 표현 범위

컴퓨터의 메모리 단위인 **바이트(Byte)**는 10진수 자릿수가 아니라 **8개의 2진수 비트(Bit)**를 묶은 단위이다.

  • 1비트(Bit): 0 또는 1 (2가지 상태)
  • 1바이트(Byte) = 8비트 가지 ()
  • 2바이트(uint16_t) = 16비트 가지 ()
    1 Byte (8 bit)              1 Byte (8 bit)
+-------------------------+-------------------------+
| b15 b14 ...          b8 | b7  b6  ...          b0 |  = 총 16 bit (uint16_t)
+-------------------------+-------------------------+
MSB (최상위 비트)                                  LSB (최하위 비트)

IMPORTANT

uint16_t는 부터 까지의 모든 정수를 담을 수 있다.
따라서 1001은 최대치(65,535)의 약 1.5%에 불과한 작은 숫자이므로 2바이트 안에 아주 여유롭게 저장된다.


2. 1001이 메모리에 저장되는 실제 이진수 구조

10진수 1001을 16진수와 2진수로 변환하면 다음과 같다.

  • 10진수: 1001
  • 16진수: 0x03E9 (16진수 1자리는 4비트, 2자리가 1바이트)
  • 2진수 (16비트): 0000 0011 1110 1001
       [ 상위 1바이트 (High Byte) ]       [ 하위 1바이트 (Low Byte) ]
비트:     0  0  0  0    0  0  1  1          1  1  1  0    1  0  0  1
16진수:          0x03                             0xE9

메모리 바이트 배치 (엔디안: Endianness)

이 2바이트가 RAM에 어떻게 배치되는지는 CPU 아키텍처에 따라 결정된다:

  1. 빅 엔디안 (Big-Endian) - 네트워크 바이트 순서(Network Byte Order):
    • 상위 바이트부터 순서대로 저장: [ 0x03 ] [ 0xE9 ]
  2. 리틀 엔디안 (Little-Endian) - x86 / AMD64 (일반적인 인텔 리눅스 서버):
    • 하위 바이트부터 역순으로 저장: [ 0xE9 ] [ 0x03 ]

네트워크 통신에서 htons()를 쓰는 이유

호스트 CPU가 리틀 엔디안(0xE9 0x03)이라도, 네트워크 선로로 전송할 때는 표준 규격인 빅 엔디안(0x03 0xE9)으로 맞춰서 보내야 상대방이 올바르게 1001로 읽을 수 있다.
그래서 htons(1001) (Host to Network Short) 함수를 호출하는 것이다.


3. 흔히 하는 오해 분석: 문자열 vs 정수형

오해 1: “2바이트니까 10진수 2자리(0~99)만 들어가는 것 아닌가?”

  • 원인: 사람이 쓰는 10진수 자릿수 개념과 컴퓨터의 2진수 바이트 개념을 혼동함.
  • 진실: 바이트는 10진수 자릿수가 아니라 진법 체계이므로, 2바이트는 가지 수를 나타냄.

오해 2: “1001은 4글자니까 4바이트가 필요한 것 아닌가?”

  • 원인: 문자(Character) 저장 방식과 숫자(Integer) 저장 방식의 차이를 인지하지 못함.
비교 항목문자열 저장 (char msg[5] = "1001")정수형 저장 (uint16_t msg = 1001)
저장 형태각 글자의 ASCII 코드값과 널문자(\0)숫자 자체를 2진수 비트(0x03E9)로 저장
메모리 구성'1'(0x31) | '0'(0x30) | '0'(0x30) | '1'(0x31) | '\0'(0x00)0x03 | 0xE9
필요 용량최소 5 바이트단 2 바이트
통신 효율텍스트 파싱(atoi) 필요, 오버헤드 큼CPU 레지스터에 즉시 로드, 처리 속도 극대화

통신 프로토콜(패킷 헤더)에서 msg_type을 문자열 "1001"이 아니라 uint16_t 숫자로 정의하는 이유가 바로 여기에 있다. 단 2바이트만으로 65,535가지의 메시지 종류를 완벽히 구분할 수 있기 때문이다.


4. C99 표준 고정 크기 정수형 (stdint.h) 정리

시스템 프로그래밍 및 네트워크 패킷 헤더 설계 시 플랫폼(32비트/64비트)에 상관없이 크기를 보장하기 위해 <stdint.h>의 타입을 사용한다.

C99 타입크기부호표현 범위대표 활용 사례
uint8_t1 Byte (8 bit)UnsignedIPv4 주소 각 자리, 플래그 비트
int8_t1 Byte (8 bit)Signed작은 오프셋, 상대 증감값
uint16_t2 Byte (16 bit)UnsignedTCP/UDP 포트 번호, 패킷 길이, 메시지 타입(msg_type)
int16_t2 Byte (16 bit)Signed센서 데이터, 오디오 샘플
uint32_t4 Byte (32 bit)Unsigned (약 42억)PCODE(0x01010101), 시퀀스 번호(seq), IPv4 주소(통합 정수)
int32_t4 Byte (32 bit)Signed일반 정수 연산
uint64_t8 Byte (64 bit)Unsigned (약 1800경)밀리초/마이크로초 타임스탬프, 누적 트래픽 바이트 수
int64_t8 Byte (64 bit)Signed대용량 DB PK, Unix Time

5. 핵심 요약

  1. **2바이트(uint16_t)**는 16개의 0과 1로 숫자를 나타내므로 최대 65,535까지 표현 가능하다.
  2. 따라서 1001은 2바이트(0x03E9) 안에 매우 여유롭게 들어간다.
  3. 숫자를 문자열로 저장하면 글자당 1바이트씩 들어서 낭비되지만, 정수형 바이너리로 저장하면 2바이트만으로도 6만 가지 이상의 상태/타입을 효율적으로 표현할 수 있다.